package com.rgs.base.tasks.task;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.rgs.base.core.exception.BaseException;
import com.rgs.base.core.model.WebApiReturnResultModel;
import com.rgs.base.core.statics.RocketMqTopicStaticClass;
import com.rgs.base.core.system.AsyncTaskStatusEnum;
import com.rgs.base.core.system.WebResponseState;
import com.rgs.base.core.util.RgsJson;
import com.rgs.base.rocketmq.RocketMqProducer;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author Ren Gaoshuai
 * @ClassName AsyncTaskRunnable
 * 任务线程
 * @date 2022-03-08 15:54
 **/
public class AsyncTaskRunnable implements Callable<WebApiReturnResultModel<Void>> {
    /**
     * 线程最大超时时间
     */
    private final static int MAX_THREAD_TIMEOUT = 300;
    /**
     * 最大错误长度
     */
    private final static int ERR_MAX_LENGTH = 500;
    private RocketMqProducer rocketMqProducer;
    private AsyncTaskRunnableBO asyncTaskRunnableBO;
    private AsyncTaskHandle asyncTaskHandle;


    public AsyncTaskRunnable(AsyncTaskRunnableBO asyncTaskRunnableBO,
                             AsyncTaskHandle asyncTaskHandle) {
        this.rocketMqProducer = SpringUtil.getApplicationContext().getBean(RocketMqProducer.class);
        this.asyncTaskRunnableBO = asyncTaskRunnableBO;
        this.asyncTaskHandle = asyncTaskHandle;
    }

    private WebApiReturnResultModel taskCall() {
        try {
            asyncTaskRunnableBO = asyncTaskHandle.execute(asyncTaskRunnableBO);
        } catch (BaseException baseException) {
            commonSetError(baseException.getMessage());
            return baseException.getWebApiReturnResultModel();
        } catch (Exception ex) {
            ex.printStackTrace();
            commonSetError(ex.getMessage());
            return WebApiReturnResultModel.ofStatus(WebResponseState.ASYNC_TASK_ERROR, ex.getMessage());
        }
        asyncTaskRunnableBO.setStatus(AsyncTaskStatusEnum.SUCCEED.getCode());
        rocketMqProducer.sendMessage(RocketMqTopicStaticClass.ASYNC_TASK_TOPIC,
                RgsJson.toJSONString(asyncTaskRunnableBO));

        return WebApiReturnResultModel.ofMessage(200, asyncTaskRunnableBO.getErrMassage(), asyncTaskRunnableBO.getFileUrl());

    }

    @Override
    public WebApiReturnResultModel<Void> call() throws Exception {
        asyncTaskRunnableBO.setStatus(AsyncTaskStatusEnum.RUNNING.getCode());
        rocketMqProducer.sendMessage(RocketMqTopicStaticClass.ASYNC_TASK_TOPIC,
                RgsJson.toJSONString(asyncTaskRunnableBO));
        FutureTask<WebApiReturnResultModel> taskFuture = new FutureTask<>(() -> taskCall());
        Thread thread = new Thread(taskFuture);
        thread.start();
        try {
            return taskFuture.get(MAX_THREAD_TIMEOUT, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException e) {
            commonSetError(WebResponseState.ASYNC_TASK_INTERRUPTED_ERROR.getStandardMessage());
            return WebApiReturnResultModel.ofStatus(WebResponseState.ASYNC_TASK_INTERRUPTED_ERROR,
                    e.getMessage());
        } catch (TimeoutException e) {
            thread.interrupt();
            commonSetError(WebResponseState.ASYNC_TASK_TIMEOUT_ERROR.getStandardMessage());
            return WebApiReturnResultModel.ofStatus(WebResponseState.ASYNC_TASK_TIMEOUT_ERROR);
        }
    }

    private void commonSetError(String errorMessage) {
        asyncTaskRunnableBO.setStatus(AsyncTaskStatusEnum.FAILED.getCode());
        asyncTaskRunnableBO.setErrMassage(
                StrUtil.sub(errorMessage, 0, ERR_MAX_LENGTH)
        );
        rocketMqProducer.sendMessage(RocketMqTopicStaticClass.ASYNC_TASK_TOPIC, RgsJson.toJSONString(asyncTaskRunnableBO));
    }
}
